#include "board.h"
#include "drv_touch_xpt2406.h"

#if TOUCH_USE_XPT2046


#define TP_ISR_PIN      GPIO_PIN_1
#define TP_ISR_GPIO     GPIOB

#define TP_SPI_CLK_PIN      GPIO_PIN_0
#define TP_SPI_CLK_GPIO     GPIOB

#define TP_SPI_MOSI_PIN      GPIO_PIN_11
#define TP_SPI_MOSI_GPIO     GPIOF

#define TP_SPI_MISO_PIN      GPIO_PIN_2
#define TP_SPI_MISO_GPIO     GPIOB

#define TP_SPI_CS_PIN      GPIO_PIN_13
#define TP_SPI_CS_GPIO     GPIOC


#define TP_CS(a)    HAL_GPIO_WritePin(TP_SPI_CS_GPIO, TP_SPI_CS_PIN, (GPIO_PinState)a)

#define TP_DCLK(a)    HAL_GPIO_WritePin(TP_SPI_CLK_GPIO, TP_SPI_CLK_PIN, (GPIO_PinState)a)

#define TP_DIN(a)    HAL_GPIO_WritePin(TP_SPI_MOSI_GPIO, TP_SPI_MOSI_PIN, (GPIO_PinState)a)

#define TP_DOUT     HAL_GPIO_ReadPin(TP_SPI_MISO_GPIO, TP_SPI_MISO_PIN)

#define TP_PEN    HAL_GPIO_ReadPin(TP_ISR_GPIO, TP_ISR_PIN)



void touch_init(void)
{
    GPIO_InitTypeDef GPIO_Initure;
    __HAL_RCC_GPIOB_CLK_ENABLE();
    __HAL_RCC_GPIOC_CLK_ENABLE();
    __HAL_RCC_GPIOF_CLK_ENABLE();

    GPIO_Initure.Pin=TP_SPI_CS_PIN;
    GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP;
    GPIO_Initure.Pull=GPIO_NOPULL;
    GPIO_Initure.Speed=GPIO_SPEED_HIGH;
    HAL_GPIO_Init(TP_SPI_CS_GPIO,&GPIO_Initure);

    GPIO_Initure.Pin=TP_SPI_CLK_PIN;
    GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP;
    GPIO_Initure.Pull=GPIO_NOPULL;
    GPIO_Initure.Speed=GPIO_SPEED_HIGH;
    HAL_GPIO_Init(TP_SPI_CLK_GPIO,&GPIO_Initure);

    GPIO_Initure.Pin=TP_SPI_MOSI_PIN;
    GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP;
    GPIO_Initure.Pull=GPIO_NOPULL;
    GPIO_Initure.Speed=GPIO_SPEED_HIGH;
    HAL_GPIO_Init(TP_SPI_MOSI_GPIO,&GPIO_Initure);

    GPIO_Initure.Pin=TP_SPI_MISO_PIN;
    GPIO_Initure.Mode=GPIO_MODE_INPUT;
    GPIO_Initure.Pull=GPIO_PULLUP;
    HAL_GPIO_Init(TP_SPI_MISO_GPIO,&GPIO_Initure);

    GPIO_Initure.Pin=TP_ISR_PIN;
    GPIO_Initure.Mode=GPIO_MODE_INPUT;
    GPIO_Initure.Pull=GPIO_PULLUP;
    HAL_GPIO_Init(TP_ISR_GPIO,&GPIO_Initure);

    TP_CS(1);
    TP_DCLK(1);
    TP_DIN(1);
}

// A/D 通道选择命令字和工作寄存器
#define CHX     0xd0    //通道Y+的选择控制字
#define CHY     0x90    //通道X+的选择控制字
//#define   CHX     0x90    //通道Y+的选择控制字
//#define   CHY     0xd0    //通道X+的选择控制字

static void Delayus(int i)
{
    while(--i);
}
//====================================================================================
static void WR_CMD(uint8_t cmd)
{
    uint8_t buf;
    uint8_t i;
    TP_CS(0);
    TP_DIN(0);
    TP_DCLK(0);
    TP_CS(0);
    for(i=0;i<8;i++)
    {
        buf=(cmd>>(7-i))&0x1;
        TP_DIN(buf);
        Delayus(5);
        TP_DCLK(1);
        Delayus(5);
        TP_DCLK(0);
    }
}
//====================================================================================
static uint16_t RD_AD(void)
{
    uint16_t buf=0,temp;
    uint8_t i;
    TP_DIN(0);
    TP_DCLK(1);
    for(i=0;i<12;i++)
    {
        TP_DCLK(0);
        Delayus(5);
        temp= (TP_DOUT) ? 1:0;
        buf|=(temp<<(11-i));
        Delayus(5);
        TP_DCLK(1);
        Delayus(5);
    }
    TP_CS(1);
    buf&=0x0fff;
    return(buf);
}

static uint32_t touch_x_min = TOUCH_X_MIN;
static uint32_t touch_x_max = TOUCH_X_MAX;
static uint32_t touch_y_min = TOUCH_Y_MIN;
static uint32_t touch_y_max = TOUCH_Y_MAX;
static uint32_t touch_dir  = 1;

void touch_set_calibrate(uint32_t x_min,uint32_t x_max,uint32_t y_min,uint32_t y_max)
{
    touch_x_min = x_min;
    touch_x_max = x_max;
    touch_y_min = y_min;
    touch_y_max = y_max;
}


static uint32_t screen_x = LCD_WIDTH;
static uint32_t screen_y = LCD_HEIGHT;
static uint32_t screen_dir = 1;

void touch_set_screen(uint32_t x,uint32_t y,uint32_t dir)
{
    screen_x = x;
    screen_y = y;
    screen_dir = dir;
}

int touch_get_raw(uint32_t *raw_x,uint32_t *raw_y)
{
    uint32_t avg_x = 0;
    uint32_t avg_y = 0;
    uint8_t nsamples = 0;

    for(uint8_t i = 0; i < 8; i++)
    {
        nsamples++;

        WR_CMD(CHX);
        avg_x+= RD_AD();

        WR_CMD(CHY);
        avg_y+= RD_AD();
    }
//  if(nsamples < 16)
//          return 0;

    if(screen_dir) // X Y DIR
    {
        *raw_y = (avg_x / nsamples);
        *raw_x = (avg_y / nsamples);
    }else
    {
        *raw_x = (avg_x / nsamples);
        *raw_y = (avg_y / nsamples);
    }
    return 1;
}

void touch_get_xy(uint32_t *x,uint32_t *y)
{
    uint32_t raw_x = 0,raw_y = 0;

    if(touch_get_raw(&raw_x,&raw_y)>0)
    {
        if(raw_x < touch_x_min) raw_x = touch_x_min;
        if(raw_x > touch_x_max) raw_x = touch_x_max;

        if(raw_y < touch_y_min) raw_y = touch_y_min;
        if(raw_y > touch_y_max) raw_y = touch_y_max;

        switch(touch_dir)
        {
            case 0: //x正向 y正向
                *x = (raw_x - touch_x_min) * screen_x / (touch_x_max - touch_x_min);
                *y = (raw_y - touch_y_min) * screen_y / (touch_y_max - touch_y_min);
                break;
            case 1: //x正向 y反向
                *x = (raw_x - touch_x_min) * screen_x / (touch_x_max - touch_x_min);
                *y = (touch_y_max - raw_y) * screen_y / (touch_y_max - touch_y_min);
                break;
            case 2: //x反向 y反向
                *x = (touch_x_max - raw_x) * screen_x / (touch_x_max - touch_x_min);
                *y = (touch_y_max - raw_y) * screen_y / (touch_y_max - touch_y_min);
                break;
            case 3: //x反向 y正向
                *x = (touch_x_max - raw_x) * screen_x / (touch_x_max - touch_x_min);
                *y = (raw_y - touch_y_min) * screen_y / (touch_y_max - touch_y_min);
                break;
        }
    }
}

void touch_raw_to_xy(uint32_t raw_x,uint32_t raw_y,uint32_t *x,uint32_t *y)
{
    if(raw_x < touch_x_min) raw_x = touch_x_min;
    if(raw_x > touch_x_max) raw_x = touch_x_max;

    if(raw_y < touch_y_min) raw_y = touch_y_min;
    if(raw_y > touch_y_max) raw_y = touch_y_max;

    switch(touch_dir)
    {
        case 0:
            *x = (raw_x - touch_x_min) * screen_x / (touch_x_max - touch_x_min);
            *y = (raw_y - touch_y_min) * screen_y / (touch_y_max - touch_y_min);
            break;
        case 1:
            *x = (raw_x - touch_x_min) * screen_x / (touch_x_max - touch_x_min);
            *y = (touch_y_max - raw_y) * screen_y / (touch_y_max - touch_y_min);
            break;
        case 2:
            *x = (touch_x_max - raw_x) * screen_x / (touch_x_max - touch_x_min);
            *y = (touch_y_max - raw_y) * screen_y / (touch_y_max - touch_y_min);
            break;
        case 3:
            *x = (touch_x_max - raw_x) * screen_x / (touch_x_max - touch_x_min);
            *y = (raw_y - touch_y_min) * screen_y / (touch_y_max - touch_y_min);
            break;
    }
}


int touch_read_status(struct touch_message *msg)
{
    uint32_t x = 0, y = 0;
    uint32_t raw_x = 0 ;
    uint32_t raw_y = 0 ;
    //static rt_uint8_t s_tp_down = 0;
    if(TP_PEN==0)
    {
            touch_get_raw(&raw_x,&raw_y);
            touch_raw_to_xy(raw_x,raw_y,&x,&y);
            //rt_kprintf("touch raw : %d  %d   cal : %d  %d\n",raw_x,raw_y,x,y);
            msg->x = x;
            msg->y = y;
            msg->event = TOUCH_EVENT_DOWN;

    }else
    {
        msg->event = TOUCH_EVENT_NONE;
    }
    return 0;
}

#endif
